﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using Clandestine.Conversations; // temp

namespace Clandestine
{
    public struct Padding // System.Drawing.Rectangle mebe.
    {
        public int Top;
        public int Bottom;
        public int Left;
        public int Right;

        public Padding(int t, int b, int l, int r)
        {
            this.Top = t;
            this.Bottom = b;
            this.Left = l;
            this.Right = r;
        }
    }

    public enum Alignment
    {
        Left,
        Right
    }

    public delegate void CancelMenu();

    public class Menu : ResizableBG
    {
        #region Properties
        private MenuItem[] items;
        public MenuItem[] Items
        {
            get { return items; }
            set
            {
                if (items != null)
                    foreach (MenuItem m in Items)
                        m.Dispose();
                items = value;
                this.InitializeSprites();
            }
        }

        public int ItemCount
        {
            get { return items.Length; }
        }

        private int cursorPosition = 0;
        public int CursorPosition
        {
            get
            {
                return cursorPosition;
            }
            set
            {
                cursorPosition = value;
                repositionCursorSprite();
            }
        }

        public bool CursorVisible
        {
            get { return Cursor.Visible; }
            set { Cursor.Visible = value; }
        }

        private bool enabled = true;
        public bool Enabled
        {
            get { return enabled; }
            set
            {
                enabled = value;
                CursorVisible = value;
            }
        }

        public override bool GluedToCamera
        {
            get { return base.GluedToCamera; }
            set
            {
                foreach (MenuItem m in Items)
                    m.Sprite.GluedToCamera = value;
                Cursor.GluedToCamera = value;
                base.GluedToCamera = value;
            }
        }

        #endregion

        public Alignment CursorSide = Alignment.Right;
        public event MenuSelect OnAnySelection;
        public event CancelMenu OnCancel;
        public Sprite Cursor;
        public Font Font = Fonts.Default2;
        public Padding Padding = new Padding(5, 5, 7, 7);

        private const float menuBaseDepth = 1000000f;
        private static int menuCount = 0;
        private static object menuCountLock = new object();

        public Menu(Size size, Alignment cur, Point pos, MenuItem[] items)
            : base(pos, size)
        {
            this.Position = pos;
            this.items = items;
            Keyboard.KeyDown += new KeyEventDelegate(OnKeyDown);

            // Now, which side shall the cursor be on? Also affects RepositionCursorSprite()
            this.CursorSide = cur;
            this.Cursor = new Sprite(((cur == Alignment.Left) ? "lcursor.png" : "rcursor.png"));

            InitializeSprites();
            repositionCursorSprite();

            // Adjust render depth (the higher the value, the 'higher' the sprite)
            lock (menuCountLock)
            {
                this.Layer = menuBaseDepth + menuCount;
                foreach (MenuItem m in items)
                    m.Sprite.Layer = this.Layer + 0.1f;
                menuCount++;
            }
            this.Cursor.Layer = this.Layer + 0.2f;

            Log.i("Menu: Created a new menu at ({0}, {1}), with {2} options. Cursor is on the {3}.", this.Position.X, this.Position.Y, ItemCount, (this.CursorSide == Alignment.Left) ? "left" : "right");
        }

        public override void Dispose()
        {
            Cursor.Dispose();
            foreach (MenuItem m in Items)
                m.Dispose();
            base.Dispose();
        }

        public void Resize()
        {
            int height = MenuItem.GetPosition(Position, Padding, items.Length, items.Length, Font).Y - 3 + Padding.Bottom + (Cursor.UnscaledHeight / 2) - this.Position.Y;
            int width = 0;
            foreach (MenuItem i in items)
                if (i.Sprite.Width > width)
                    width = i.Sprite.Width;
            width += (Padding.Left * 2) + Padding.Right + Cursor.UnscaledWidth;

            Resize(new Size(width, height));
            repositionCursorSprite();
        }

        public void InitializeSprites()
        {
            if (items.Length == 0)
                this.Enabled = false;

            for (int i = 0; i < items.Length; i++)
                items[i].RenderSprite(MenuItem.GetPosition(this.Position, this.Padding, i, items.Length, this.Font), this.Font, this.Layer + 0.1f);

            repositionCursorSprite();
        }

        public void WaitForMenu()
        {
            bool menuComplete = false;
            MenuSelect selection = delegate
            {
                menuComplete = true;
            };
            this.OnAnySelection += selection;
            while (!menuComplete)
                System.Threading.Thread.Sleep(100);
            this.OnAnySelection -= selection;
        }

        private void OnKeyDown(Key Key)
        {
            if (enabled)
                switch (Key)
                {
                    case Key.Up:
                        if (CursorPosition > 0)
                            CursorPosition--;
                        break;

                    case Key.Down:
                        if (CursorPosition < (items.Length - 1))
                            CursorPosition++;
                        break;

                    case Key.Select:
                        items[CursorPosition].Select();
                        if (OnAnySelection != null)
                            OnAnySelection(this);
                        break;

                    case Key.Cancel:
                        if (OnCancel != null)
                        {
                            OnCancel();
                            if (OnAnySelection != null) // to stop wait events
                                OnAnySelection(this);
                        }
                        break;
                }
        }

        private void repositionCursorSprite()
        {
            Cursor.Position = MenuItem.GetPosition(this.Position, this.Padding, CursorPosition, this.ItemCount, this.Font);
            Cursor.Y += (this.Font.Height / 2) - (Cursor.UnscaledHeight / 2);

            // Decide which side of the menu it should be
            if (CursorSide == Alignment.Right)
                Cursor.X += (this.Width - this.Padding.Right - this.Padding.Left - Cursor.UnscaledWidth);
        }

    }
}
